#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 
#include <stdint.h>
#include "util.h"
#include <inttypes.h>

/********************************************************
  这个是TGS进程。其与AS加密通信的密钥为0x3031323334353637，
  即可见字符串"01234567"的ASCII。其与SS加密通信的密钥为
  0x4142434445464748，即"ABCDEFGH"。
*********************************************************/
#define K_TGS 0x3031323334353637
#define K_SS 0x4142434445464748

int main() {
    srand(time(NULL));
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr, client_addr;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(22222); 

    int res = bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
    if (res != 0) {
        printf("errno %d: %s\n", errno, strerror(errno));
        return 1;
    }

    listen(listenfd, 10); 

    int client_len = sizeof(struct sockaddr_in);
    char client_ip[20];
    char client_ip_port[30];
    printf("Ticket-Granting server started!\n");
    while (1) {
        printf("Listening...\n");
        connfd = accept(listenfd, (struct sockaddr*)&client_addr, (socklen_t*)&client_len); 
        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
        sprintf(client_ip_port, "%s:%d", client_ip, ntohs(client_addr.sin_port));
        printf("Accepted %s\n", client_ip_port);

        /* 接收CD两则消息 */
        multi_msg message_cd = new_multi_msg();
        mm_sock_read(&message_cd, connfd);
        multi_msg message_c = new_multi_msg();
        mm_loads(&message_c, message_cd.msgs + 0);
        /* 从C中提取B(TGT)，并从TGT中得到client id和k_client_tgs */
        multi_msg message_b = new_multi_msg();
        mm_decrypt_loads(&message_b, message_c.msgs + 1, K_TGS);
        printf("(Decrypted from TGT) Client ID: %s\n", message_b.msgs[0].data);
        printf("(Decrypted from TGT) Client address when connecting to AS: %s\n", message_b.msgs[1].data);
        uint64_t k_client_tgs = 0;
        for (int i = 0; i < 8; ++i) {
            k_client_tgs |= ((uint64_t)message_b.msgs[2].data[i] << (i * 8));
        }
        printf("(Decrypted from TGT) k_client_tgs: %016" PRIx64 "\n", k_client_tgs);
        
        /* 用从B(TGT)中解密获得的k_client_tgs来解密D消息 */
        multi_msg message_d = new_multi_msg();
        mm_decrypt_loads(&message_d, message_cd.msgs + 1, k_client_tgs);
        mm_free(&message_cd);
        printf("(Decrypted from D) Client ID: %s\n", message_d.msgs[0].data);
        uint32_t stamp = 0;
        for (int i = 0; i < 4; ++i) {
            stamp |= ((uint32_t)message_d.msgs[1].data[i] << (i * 8));
        }
        printf("(Decrypted from D) Timestamp: %" PRIu32 "\n", stamp);

        

        /* 返回EF两则消息给Client */
        multi_msg message_ef = new_multi_msg();
        if (strcmp((char*)message_b.msgs[0].data, (char*)message_d.msgs[0].data) == 0) {  // 认证成功
            multi_msg message_st = new_multi_msg();
            uint64_t k_client_ss = rand_uint64();
            printf("Generate a new k_client_ss: %016" PRIx64 "\n", k_client_ss);
            mm_build(&message_st, "ssk", message_b.msgs[0].data, client_ip_port, k_client_ss);
            octet_string eos_st = new_octet_string();
            mm_dumps_encrypt(&eos_st, &message_st, K_SS);
            mm_free(&message_st);

            multi_msg message_e = new_multi_msg();
            mm_build(&message_e, "so", message_c.msgs[0].data, &eos_st);
            os_free(&eos_st);
            octet_string os_e  = new_octet_string();
            mm_dumps(&os_e, &message_e);
            mm_free(&message_e);

            multi_msg message_f = new_multi_msg();
            mm_build(&message_f, "k", k_client_ss);
            octet_string eos_f = new_octet_string();
            mm_dumps_encrypt(&eos_f, &message_f, k_client_tgs);
            mm_free(&message_f);

            mm_build(&message_ef, "soo", "success", &os_e, &eos_f);
        }
        else {  // 认证失败
            mm_build(&message_ef, "s", "fail");
        }
        mm_sock_write(connfd, &message_ef);
        mm_free(&message_ef);
        mm_free(&message_b);
        mm_free(&message_c);
        mm_free(&message_d);


        close(connfd);
        sleep(1);
        putchar('\n');
     }
}
